use crate::core::error::AppError;
use std::{
    ffi::OsStr,
    path::{Path, PathBuf},
    process::{Command, Output},
    str::FromStr
};
use log::{info, warn};
use serde::{Deserialize, Serialize};

/// 支持的CPU架构类型
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ArchType {
    X86_64,
    AArch64,
    RISCV64,
    MIPS64EL,
}

impl FromStr for ArchType {
    type Err = AppError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "x86_64" | "amd64" => Ok(ArchType::X86_64),
            "aarch64" | "arm64" => Ok(ArchType::AArch64),
            "riscv64" => Ok(ArchType::RISCV64),
            "mips64el" => Ok(ArchType::MIPS64EL),
            _ => Err(AppError::ArchError(format!("不支持的架构: {}", s))),
        }
    }
}

/// QEMU 模拟器控制器
pub struct QemuManager {
    bin_path: PathBuf,
    arch: ArchType,
}

impl QemuManager {
    /// 初始化跨架构模拟环境
    pub fn new(target_arch: ArchType) -> Result<Self, AppError> {
        let bin_path = Self::find_qemu_binary(target_arch)?;
        Ok(Self {
            bin_path,
            arch: target_arch,
        })
    }

    /// 查找可用的QEMU二进制路径
    fn find_qemu_binary(arch: ArchType) -> Result<PathBuf, AppError> {
        let qemu_bin_name = match arch {
            ArchType::X86_64 => "qemu-x86_64-static",
            ArchType::AArch64 => "qemu-aarch64-static",
            ArchType::RISCV64 => "qemu-riscv64-static",
            ArchType::MIPS64EL => "qemu-mips64el-static",
        };

        // 搜索标准路径
        let paths = [
            "/usr/bin",
            "/usr/local/bin",
            "/usr/libexec",
        ];

        for path in paths {
            let full_path = Path::new(path).join(qemu_bin_name);
            if full_path.exists() {
                return Ok(full_path);
            }
        }

        Err(AppError::ArchError(format!("未找到QEMU模拟器: {}", qemu_bin_name)))
    }

    /// 在chroot环境中执行跨架构命令
    pub fn execute_in_chroot(
        &self,
        chroot_dir: &Path,
        command: &str,
        args: &[&str],
    ) -> Result<Output, AppError> {
        let status = Command::new("chroot")
            .arg(chroot_dir)
            .arg(self.bin_path.as_os_str())
            .arg("--")
            .arg(command)
            .args(args)
            .status()?;

        if !status.success() {
            return Err(AppError::QemuError(format!(
                "QEMU执行失败: {} (退出码: {})",
                command,
                status.code().unwrap_or(-1)
            )));
        }
        Ok(Output {
            status,
            stdout: Vec::new(),
            stderr: Vec::new(),
        })
    }

    /// 转换二进制文件格式
    pub fn convert_binary(
        &self,
        input_path: &Path,
        output_path: &Path,
    ) -> Result<(), AppError> {
        info!("正在转换二进制文件: {} → {}", input_path.display(), output_path.display());
        
        // 使用objcopy转换目标格式
        let objcopy_tool = match self.arch {
            ArchType::X86_64 => "objcopy",
            ArchType::AArch64 => "aarch64-linux-gnu-objcopy",
            ArchType::RISCV64 => "riscv64-linux-gnu-objcopy",
            ArchType::MIPS64EL => "mips64el-linux-gnuabi64-objcopy",
        };

        let status = Command::new(objcopy_tool)
            .args(&[
                "-O",
                "binary",
                "--set-section-flags .text=alloc,load,readonly",
                input_path.to_str().unwrap(),
                output_path.to_str().unwrap(),
            ])
            .status()?;

        if status.success() {
            info!("二进制转换成功");
            Ok(())
        } else {
            Err(AppError::QemuError("二进制格式转换失败".into()))
        }
    }

    /// 配置跨架构依赖库
    pub fn setup_binfmt(&self) -> Result<(), AppError> {
        info!("正在注册binfmt_misc...");
        let arch_name = match self.arch {
            ArchType::X86_64 => "x86_64",
            ArchType::AArch64 => "arm",
            ArchType::RISCV64 => "riscv",
            ArchType::MIPS64EL => "mips",
        };

        let status = Command::new("systemctl")
            .args(&["restart", "systemd-binfmt.service"])
            .status()?;

        if !status.success() {
            warn!("binfmt服务重启失败，尝试手动注册");
            let register_cmd = format!(
                ":{}:M::\\x7f\\x45\\x4c\\x46\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00:{arch_byte}::/usr/bin/qemu-{arch}-static:F",
                arch_byte = match self.arch {
                    ArchType::X86_64 => "3e",
                    ArchType::AArch64 => "b7",
                    _ => "00"
                },
                arch = arch_name
            );

            let status = Command::new("sh")
                .arg("-c")
                .arg(format!("echo '{}' > /proc/sys/fs/binfmt_misc/register", register_cmd))
                .status()?;

            if !status.success() {
                return Err(AppError::QemuError("binfmt_misc注册失败".into()));
            }
        }
        Ok(())
    }
}

/// 跨架构环境构建器
pub struct CrossEnvBuilder {
    base_dir: PathBuf,
    target_arch: ArchType,
    packages: Vec<String>,
}

impl CrossEnvBuilder {
    pub fn new(base_dir: impl AsRef<Path>, arch: ArchType) -> Self {
        Self {
            base_dir: base_dir.as_ref().to_path_buf(),
            target_arch: arch,
            packages: vec![],
        }
    }

    /// 添加必备的依赖包
    pub fn with_package(mut self, pkg: &str) -> Self {
        self.packages.push(pkg.to_string());
        self
    }

    /// 构建完整的跨架构环境
    pub fn build(self) -> Result<(), AppError> {
        let qemu = QemuManager::new(self.target_arch)?;
        
        // 安装基础运行库
        info!("正在安装跨架构基础环境");
        let mut cmd = self.get_pkg_manager();
        cmd.arg("install")
            .args(&self.packages)
            .status()?;

        // 配置binfmt
        qemu.setup_binfmt()?;

        // 复制QEMU解释器
        let qemu_target_path = self.base_dir.join("usr/bin").join(qemu.bin_path.file_name().unwrap());
        std::fs::copy(&qemu.bin_path, qemu_target_path)?;

        Ok(())
    }

    fn get_pkg_manager(&self) -> Command {
        match self.target_arch {
            ArchType::AArch64 => {
                let mut cmd = Command::new("apt");
                cmd.arg("-o")
                    .arg("APT::Architecture=arm64")
                    .arg("-o")
                    .arg("APT::Architectures=arm64");
                cmd
            }
            _ => Command::new("apt"),
        }
    }
}